////////////////////
//Multiplayer Games Core based on XMPP
//Comunication Module
////////////////////

PRESENCE.GAME.COMUNICATION = (function(P,$,undefined){
  
	//////////////////////////////////////////////
  //       GAME COMUNICATION VARIABLES        //
  //////////////////////////////////////////////
	 
  var connection = null;
  var iqStanzaID = new Array();
	iqStanzaID['gameRequest'] = "gameRequestID";
	iqStanzaID['gameRequestFinish'] = "gameRequestFinishID";
	iqStanzaID['gameAction'] = "gameActionID";

  var getIQStanzaID = function(){
		return iqStanzaID;
	}
	
	/////////////////////////////////
	//    COMUNICATION METHODS     //
	/////////////////////////////////
	
  var init = function(myConnection){
    connection = myConnection;
		//addHandler:(callback, namespace to match, stanza name, stanza type, stanza id , stanza from, options)
		if(connection){
			connection.addHandler(handleRequestGameIQStanza,null, "iq", "get",iqStanzaID['gameRequest'], null);
      connection.addHandler(handleIQResultFromGameRequest,null, "iq", "result",iqStanzaID['gameRequest'], null);
			connection.addHandler(handleIQErrorFromGameRequest,null, "iq", "error",iqStanzaID['gameRequest'], null);
      connection.addHandler(handleIQResultFromGameRequestFinish,null, "iq", "result", iqStanzaID['gameRequestFinish'], null);
      connection.addHandler(handleActionIQStanza,null, "iq", "result", getIdForIqAction("gameId"), null);
		}
  };
	
	
	
	/////////////////////
  // MANAGE GAME REQUESTS
  /////////////////////
	
	//SEND GAME REQUEST
	//Jid == Game Room or User to send the request game stanza
	//Game == Game to play with configuration
	var sendIQStanzaToRequestGame = function (jid,game){
		var optionIndex=0;
		var optionsSize=Object.keys(game.options).length;
		
    var iq = $iq({to: jid, type: "get", id: iqStanzaID['gameRequest']})
    .c("query", {xmlns: "urn:ietf:params:xml:ns:xmpp-stanzas"})
		 .c("game", {id: game.id, name: game.name})
		   .c("players", {})
			 
			  $.each(game.players, function(index, value) {
					if(index==game.players.length-1){
						iq.c("player", {id: value.id}).t(value.name).up().up()
					} else {
						iq.c("player", {id: value.id}).t(value.name).up()
					}
        });
				
				iq.c("options", {})
				
				for (var key in game.options) {
					if(optionIndex == optionsSize-1){
						iq.c("option", {name: key}).t(game.options[key]).up().up()
					} else {
						iq.c("option", {name: key}).t(game.options[key]).up()
					}
					optionIndex=optionIndex+1;
        }
				
    connection.sendIQ(iq);
  };
	
	
	//RECEIVE GAME REQUEST
	var handleRequestGameIQStanza = function(iq){
    var from = iq.getAttribute("from");
    var slug = from.split("@")[0];
    var gameId = "";
    var gameName = "";
    var players = []
    var options = new Array();
    
    //Build game object
    var gameTag = iq.getElementsByTagName('game');
  
    if (gameTag.length == 1) {
      var gameElement = gameTag[0];
      gameName = $(gameElement).attr("name")
      gameId = $(gameElement).attr("id")
      
      var playersTag = iq.getElementsByTagName('players');
      if (playersTag.length > 0) {
          $.each($(playersTag).children(), function(index, value) {
            players.push(new P.GAME.player($(value).attr("id"),$(value).text()))
          });
      }
      
      var optionsTag = iq.getElementsByTagName('options');
      if (optionsTag.length > 0) {
        $.each($(optionsTag).children(), function(index, value) {
          options[$(value).attr("name")]=$(value).text();
        });
      }
    }
    
		P.GAME.updateLogicAfterReceivedGameRequest(slug,gameId,gameName,players,options)
    return true;
  }
  
	
	
	/////////////////////
  // MANAGE GAME REQUESTS RESPONSES
  /////////////////////
	
	//SEND GAME REQUEST RESPONSE
  var sendIQStanzaToResponseGameRequest = function(jid,result){
    var iq = $iq({to: jid, type: "result", id: iqStanzaID['gameRequest']})
    .c("query", {xmlns: "urn:ietf:params:xml:ns:xmpp-stanzas"})
    .c("response").t(result);
    connection.sendIQ(iq);
  }
	
	//RECEIVE GAME REQUEST RESPONSE
  var handleIQResultFromGameRequest = function(iq){
		
    var from = iq.getAttribute("from");
    var slug = from.split("@")[0]; 
    var queryTag = iq.getElementsByTagName('query');
    
    if (queryTag.length > 0) {
      var queryElement = queryTag[0];
      var response = queryElement.getElementsByTagName('response');
      
      if(response.length == 1){
        P.GAME.updateLogicAfterReceivedGameRequestResponse(slug,$(response).text())
        return true;
      }
    }
		
    return true;
  }
  
	//RECEIVE GAME REQUEST ERROR RESPONSE
	var handleIQErrorFromGameRequest = function(iq){
    var from = iq.getAttribute("from");
    var slug = from.split("@")[0]; 
    P.GAME.updateLogicAfterReceivedGameRequestError(slug)
    return true;
  }
	
	
	/////////////////////
  // MANAGE GAME REQUESTS CANCELATIONS
  /////////////////////
	
  //SEND GAME REQUEST CANCELATION
  var sendIQStanzaToFinishGame = function(jid){
    var iq = $iq({to: jid, type: "result", id: iqStanzaID['gameRequestFinish']})
    .c("game", {xmlns: "urn:ietf:params:xml:ns:xmpp-stanzas"})
    .c("status").t("finish");
    connection.sendIQ(iq);
  }

	//RECEIVE GAME REQUEST CANCELATION
  var handleIQResultFromGameRequestFinish = function(iq){
    var from = iq.getAttribute("from");
    var slug = from.split("@")[0]; 
    var gameTag = iq.getElementsByTagName('game');
    
    if (gameTag.length > 0) {
      var gameTagElement = gameTag[0];
      var response = gameTagElement.getElementsByTagName('status');
      
      if(response.length == 1){
        var gameStatus = $(response).text();
        P.GAME.updateLogicAfterReceivedGameRequestCancelation(slug,gameStatus)
        return true;
      }
    }
    return true;
  }


	
	/////////////////////
  // MANAGE ACTION EXCHANGE 
  /////////////////////
	
  function action(){}
	
	
	//SEND ACTIONS
	
	var sendIQStanzaWithAction = function (jid,gameId,action){
    var iqId = getIdForIqAction(gameId);
    var iq = $iq({to: jid, type: "result", id: iqId})
    .c("query", {xmlns: "urn:ietf:params:xml:ns:xmpp-stanzas"})
     .c("game", {id: gameId})
       .c("action", {type: action.type})
		action.type=null;	  
    iq = genetareIQStanzaWithObject(iq,action)
    return connection.sendIQ(iq);
  };
	
	var getIdForIqAction = function (gameId){
		return iqStanzaID['gameAction'] + "_" + gameId;
	}
	
	var genetareIQStanzaWithObject = function(iq,object){

		if(typeof object != "object"){
			return iq;
		}
		
		var childs=Object.keys(object).length;
    var childsCounter = 0;
		
		$.each(object, function(index, value) {

		  if(value==null){
			  return;
			}
			
      if((typeof value == "object")){
        //Complex object
				var object_type = "object"
				
				if(value.constructor.toString().indexOf("Array")!=-1){
					object_type = "array"
				}
				
				iq.c(index, {type: object_type})
				iq = genetareIQStanzaWithObject(iq,value)
				
      } else {
				//Simple object
				
				var data_type = (typeof value)
				var index_type = (typeof index)
				
        switch (data_type){
				  case "number":
				    value = value + "";
				    break;
				  case "boolean":
						value = value.toString();
				    break;
				  case "string":
            //do nothing
            break;
				  default: 
					  break;
				}
				
				switch (index_type){
          case "number":
					   //case: Array
					   index = "item";
            break;
          case "string":
            //do nothing
            break;
          default: 
            break;
        }
				
				if(childsCounter==childs-1){
					iq.c(index, {type: data_type}).t(value).up().up()
				} else {
					iq.c(index, {type: data_type}).t(value).up()
				}
      }
      childsCounter++;
    });
		return iq;
	}


  //RECEIVE ACTIONS
	
  var handleActionIQStanza = function(iq){
		var from = iq.getAttribute("from");
    var slug = from.split("@")[0]; 
    var queryTags = iq.getElementsByTagName('query');
    
    if (queryTags.length == 1) {
      var queryElement = queryTags[0];
      var gameTags = queryElement.getElementsByTagName('game');
      
      if(gameTags.length == 1){
        var game = gameTags[0];
				var gameId = $(game).attr("id")
				var actionElements = game.getElementsByTagName('action');
				$.each(actionElements, function(index, value) {
            var myaction = buildActionObject(value)
						PRESENCE.GAME[gameId].onActionReceived(myaction)
        });
      }
    }
    return true;
	}

	var buildActionObject = function (actionTag){
		var myaction = new action();
		var type = $(actionTag).attr("type")
		myaction.type = type;
		myaction = buildComplexObject(myaction,actionTag)
		return myaction
	}
	
	var buildComplexObject = function(parent,childs){
    $.each($(childs).children(), function(index, value) {
       if ($(value).children().length>0) {
         //Complex object
				 if ($(value).attr("type")=="array"){
				 	  parent[value.tagName] = new Array()
				 } else {
				 	  parent[value.tagName] = new Object()
				 }
				 parent[value.tagName]= buildComplexObject(parent[value.tagName],$(value))
				 
       } else {
        //Simple object
				var myvalue = null
				var stringValue = $(value).text()
				
        //Check dataformat
				var data_type = $(value).attr("type")
				
        switch (data_type){
          case "number":
						if(! isNaN(+(stringValue))){
	            //$(value).text() is a string which contains a number
	            myvalue = +(stringValue)
	          }
            break;
          case "boolean":
					  if((stringValue=="true")||(stringValue=="false")){
							myvalue = (stringValue === "true")
						}
            break;
					case "string":
            myvalue = stringValue
            break;
          default: 
            break;
        }
				   
         //Is parent an array element and value an array item?
         if((parent.constructor.toString().indexOf("Array")!=-1)&&(value.tagName == "item")){
            parent.push(myvalue)
         } else {
				 	  parent[value.tagName]=myvalue
				 }
        
       }
    });
		return parent
	}


  
	/////////////////////////////
	//REMOVE CONNECTION HANDLERS
	/////////////////////////////
	
  var removeHandler = function(handler){
		connection.deleteHandler(handler);
	}
	
	var addHandler = function(gameId){
		return connection.addHandler(handleActionIQStanza, null, "iq", "result", getIdForIqAction(gameId) , null);
	}


  return {
    init: init,
		sendIQStanzaToRequestGame: sendIQStanzaToRequestGame,
		handleRequestGameIQStanza: handleRequestGameIQStanza,
		sendIQStanzaToResponseGameRequest: sendIQStanzaToResponseGameRequest,
		handleIQResultFromGameRequest: handleIQResultFromGameRequest,
		sendIQStanzaToFinishGame: sendIQStanzaToFinishGame,
    handleIQResultFromGameRequestFinish: handleIQResultFromGameRequestFinish,
		sendIQStanzaWithAction: sendIQStanzaWithAction,
    handleActionIQStanza: handleActionIQStanza,
		addHandler : addHandler,
		removeHandler: removeHandler,
		getIQStanzaID : getIQStanzaID
  };

}) (PRESENCE, jQuery);



